﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;



namespace helicopterFight
{
    public class TestState : State
    {
        private String nazwa = "Sandbox";
        public Game1 game = null;
        public List<GameObject> obiekty = new List<GameObject>();
        //CameraFPS kamera = new CameraFPS();
        public CameraTPP kamera = new CameraTPP();
        public Controls sterowanie = new Controls();
        public Network network;
        public NetworkSession netSession;
        String gracze = "";
        private bool multiplayer = false;

        public bool Multiplayer
        {
            get { return multiplayer; }
            set { multiplayer = value; }
        }
        private GameTime gameTime;
        private Random rand = new Random();
        public String stats = "";
        public GameTime GameTime
        {
            get { return gameTime; }
            set { gameTime = value; }
        }
        public Compass compass;
        public Altimeter altimeter;
        public Minimap minimap;

        public HelicopterObject helitmp = new HelicopterObject();
        public HelicopterObject helikopter1 = new HelicopterObject();        

        GameObject terrain = new GameObject();
        public Terrain teren = new Terrain(null, "Nazwa", "hard", "1:50");
        Sky niebo = new Sky();
        GameObject airport = new GameObject();
        GameObject missile = new GameObject();

        KeyboardState oldKeybState;

        public static Cue missileCue;
        public static Cue heliCue, oppCue;
        private AudioEmitter emitter = new AudioEmitter();
        public static AudioEmitter oppEmitter = new AudioEmitter();

        /*
        public AudioEmitter[] opponents = new AudioEmitter[5];
        public const int LOCAL_HELI = 0,
                         HELI_1 = 1,
                         HELI_2 = 2,
                         HELI_3 = 3,
                         HELI_4 = 4;
        */ 

        private AudioListener listener = new AudioListener();
        private AudioListener listener2 = new AudioListener();

        public  float distance = 5;

        public Texture2D stat;
        bool drawstats = false;

        RenderTarget2D renderTarget;

        SpriteFont font1 = null;

        //METODY ------------------------------


        private Vector3 CalculateLocation(float angle, float distance)
        {
            return new Vector3(
                (float)Math.Cos(angle) * distance,
                0,
                (float)Math.Sin(angle) * distance);
        }


        public void setContent(Game1 gam)
        {
            game = gam;
        }
        
        public String getNazwa()
        {
            return nazwa;
        }

        public void initialize()
        {
            kamera.init(game.graphics);
            oldKeybState = Keyboard.GetState();
            Game1.konsola.addMessage("Start/stop silnika - x");
            Game1.konsola.addMessage("Wznoszenie/opadanie - e/c");
            Game1.konsola.addMessage("Sterowanie - WSAD");
            Game1.konsola.addMessage("InGameMenu/pauza - ESC");
            Game1.konsola.addMessage("Wlacz/Wylacz konsole - k");

            renderTarget = new RenderTarget2D(
                game.GraphicsDevice,
                game.GraphicsDevice.PresentationParameters.BackBufferWidth,
                game.GraphicsDevice.PresentationParameters.BackBufferHeight,
                1,
                game.GraphicsDevice.PresentationParameters.BackBufferFormat);

            compass = new Compass(game);
            altimeter = new Altimeter(game, helikopter1);
            minimap = new Minimap(game, obiekty);
            missileCue = MenuState.soundBank.GetCue("missile");
            heliCue = MenuState.soundBank.GetCue("helicopter");
            if (multiplayer)
                oppEmitter.Position = Vector3.Zero;
            oppCue = MenuState.soundBank.GetCue("helicopter");
        }

        public Vector3 randomPosition()
        {
            int index = rand.Next(teren.Respawns.GetLength(0));
            return teren.Respawns[index];
        }

        public void loadContent() 
        {
            //Helikopter
            Model helic = game.Content.Load<Model>("models/helicopter");
            helikopter1.model = helic;
            helikopter1.scale = 0.02f;
            helikopter1.position = randomPosition();
            helikopter1.init(this);

            //Ladowisko?!
            airport.model = game.Content.Load<Model>("models/ladowisko");
            airport.position.X = 100;
            airport.position.Z = 100;
            airport.position.Y = -10;

            //Teren
            //teren.init(game, this, 1);
            niebo.init(game);
            niebo.target = helikopter1;

            //(new Missile()).init(game, null);
            new Explosion(game);

            obiekty.Add(niebo);
            obiekty.Add(teren);
            obiekty.Add(helikopter1);
            

            stat = game.Content.Load<Texture2D>("bgr/stats");
            font1 = game.Content.Load<SpriteFont>("fonts/SpriteFont1");

            network = new Network(game, this, helikopter1);
        }

        //TUTAJ jest WAZNE cos PATRZ na TO TERAZ i Jutro .
        public void analizeCollision()
        {
            int i = 0;
            while (i < obiekty.Count)
            {
                int j = 0;
                GameObject ob = obiekty[i];

                while (j < obiekty.Count)
                {
                    GameObject ob2 = obiekty[j];
                    if (ob is HelicopterObject && ob2 is HelicopterObject)
                    {
                        HelicopterObject heli1 = ob as HelicopterObject;
                        HelicopterObject heli2 = ob2 as HelicopterObject;
                        if (heli1.HeliSphere.Contains(heli2.HeliSphere) == ContainmentType.Intersects
                            && heli1 != heli2
                            && heli1.IsAlive && heli2.IsAlive)
                        {
                            heli1.IsAlive = false;
                            heli2.IsAlive = false;
                            heli1.points--;
                            heli1.resetSpeed();
                            heli2.points--;
                            heli2.resetSpeed();
                            createExplosion(heli2.position);
                            createExplosion(heli1.position);
                            if (multiplayer)
                            {
                                network.fillRockets(heli1);
                                network.fillRockets(heli2);
                                network.sendStats();
                            }
                        }
                    }
                    else if (ob is HelicopterObject && ob2 is Terrain)
                    {
                        Terrain terrain = ob2 as Terrain;
                        HelicopterObject heli = ob as HelicopterObject;
                        int heliX = (int)(heli.position.X / 30);
                        int heliZ = -(int)(heli.position.Z / 30);

                        if ( (heliX > terrain.HeightData.GetUpperBound(0)
                            || heliX < 0
                            || heliZ < 0
                            || heliZ > terrain.HeightData.GetUpperBound(1) ) 
                            && heli.IsAlive )
                        {
                            heli.IsAlive = false;
                            heli.points--;
                            createExplosion(heli.position);
                            if (multiplayer)
                                network.sendStats();
                        }

                        if (heliX < terrain.HeightData.GetUpperBound(0)
                            && heliZ < terrain.HeightData.GetUpperBound(1)
                            && heliX >= 0 && heliZ >= 0)
                            if (heli.IsAlive && terrain.HeightData[heliX, heliZ] * 30 >= heli.position.Y - 3)
                            {
                                heli.IsAlive = false;
                                heli.points--;
                                createExplosion(heli.position);
                                if (multiplayer)
                                    network.sendStats();
                            }
                    }
                    else if (ob is HelicopterObject && ob2 is Missile)
                    {
                        Missile missile = ob2 as Missile;
                        HelicopterObject heli = ob as HelicopterObject;
                        if (missile.MissileSphere.Contains(heli.HeliSphere) == ContainmentType.Intersects
                            && missile.Owner != heli
                            && !missile.Ignore
                            && heli.IsAlive)
                        {
                            heli.IsAlive = false;
                            missile.Active = false;
                            missile.Owner.points++;
                            missile.Owner.resetMissiles();      //EKSPERIMENTAL
                            createExplosion(heli.position);
                            createExplosion(missile.position);
                            Missile rock = ob2 as Missile;
                            if (multiplayer)
                            {
                                network.sendStats();
                                network.fillRockets(heli);
                                network.fillRockets(rock.Owner);
                                network.hit(missile, heli);
                            }
                        }
                    }
                    else if (ob is Missile && ob2 is Terrain)
                    {
                        Terrain terrain = ob2 as Terrain;
                        Missile miss = ob as Missile;
                        int missX = (int)(miss.position.X / 30);
                        int missZ = -(int)(miss.position.Z / 30);

                        if (missX < terrain.HeightData.GetUpperBound(0)
                            && missZ < terrain.HeightData.GetUpperBound(1)
                            && missX >= 0 && missZ >= 0)
                            if (miss.Active && terrain.HeightData[missX, missZ] * 30 >= miss.position.Y - 3)
                            {
                                miss.Active = false;
                                createExplosion(miss.position);
                            }
                    }
                    j++;
                }

                i++;
            }
        }

        public String parseList()
        {
            String abc = "";
            foreach (GameObject go in obiekty)
            {
                if (go is HelicopterObject)
                {
                    HelicopterObject heli = go as HelicopterObject;
                    abc += heli.name + " : " + heli.points + "\n";
                }
            }
            return abc;
        }

        public void update() 
        {
            listener.Position = kamera.getPos();  
            listener2.Position = helikopter1.position;

            heliCue.Apply3D(listener, emitter);

           if(multiplayer)
            oppCue.Apply3D(listener2, oppEmitter);
            if (!TestState.oppCue.IsPlaying && multiplayer)
                oppCue.Play();


            foreach (GameObject ob in obiekty)
            {
                if (!(ob is HelicopterObject))
                {
                    continue;
                }

                HelicopterObject ho = ob as HelicopterObject;

                if (ho.respawn() && (!multiplayer || network.getSession().IsHost))
                {
                    ho.setPosition(randomPosition());
                    if (multiplayer)
                        network.sendRespawn(ho);
                    ho.resetMissiles();
                    ho.resetSpeed();
                }
            }

            
            int index = 0;
            while (index < obiekty.Count)
            {
                if (obiekty[index] is Missile
                    && !((Missile)obiekty[index]).Active )
                    obiekty.RemoveAt(index);
                else if (obiekty[index] is Explosion
                    && !((Explosion)obiekty[index]).visible)
                    obiekty.RemoveAt(index);
                else
                    index++;
            }
            
            kamera.Update();
            foreach (GameObject ob in obiekty)
            {
                ob.update();
            }

            KeyboardState ks = Keyboard.GetState();


            if (ks.IsKeyDown(Game1.sterowanie.EngineStart) && !oldKeybState.IsKeyDown(Game1.sterowanie.EngineStart))
            {
                if(!heliCue.IsPlaying)
                    heliCue.Play();
                else if (heliCue.IsPaused)
                    heliCue.Resume();
                else if (heliCue.IsPlaying)
                    heliCue.Pause();
                helikopter1.engine();
            }

            if (ks.IsKeyDown(Game1.sterowanie.FlyUp))
            {
                helikopter1.moveUp();
            }
            else if (ks.IsKeyDown(Game1.sterowanie.FlyDown))
            {
                helikopter1.moveDown();
            }

            if (ks.IsKeyDown(Game1.sterowanie.FlyForward))
            {
                if(MenuState.gameMusic.Name == "przyczajka")
                    MenuState.gameMusic.Dispose();
                    if (!MenuState.gameMusic.IsPlaying)
                    {
                        MenuState.gameMusic = MenuState.soundBank.GetCue("gonitwa");
                        MenuState.gameMusic.Play();
                    }
               
                helikopter1.moveForward();
            }
            else if (ks.IsKeyDown(Game1.sterowanie.FlyBackward))
            {
                helikopter1.moveBackward();
            }

            if (ks.IsKeyDown(Game1.sterowanie.FlyLeft))
            {
                helikopter1.rotateLeft();
            }
            else if (ks.IsKeyDown(Game1.sterowanie.FlyRight))
            {
                helikopter1.rotateRight();
            }

            if (ks.IsKeyDown(Game1.sterowanie.ShootMissile) && !oldKeybState.IsKeyDown(Game1.sterowanie.ShootMissile))
                helikopter1.shootMissile(network);

            if (ks.IsKeyDown(Game1.sterowanie.ConsoleOnOff) && !oldKeybState.IsKeyDown(Game1.sterowanie.ConsoleOnOff))
                Game1.konsola.enabled = !Game1.konsola.enabled;

            if (ks.IsKeyDown(Game1.sterowanie.StatsOnOff))
                drawstats = true;

            oldKeybState = ks;

            if (multiplayer)
                network.UpdateNetworkSession();

            analizeCollision();
        }

        public void drawStats()
        {
            int px = (game.graphics.PreferredBackBufferHeight-500)/2;
            int py = (game.graphics.PreferredBackBufferWidth-400)/2;
            game.spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            game.spriteBatch.Draw(stat, new Rectangle(py, px, 500, 400), new Color(255, 255, 255, 130));
            if (multiplayer)
            {
                netSession = network.getSession();
                gracze = stats;
                game.spriteBatch.DrawString(font1, gracze, new Vector2(py+30, px+50), Color.Black);
                game.spriteBatch.DrawString(font1, "Your missiles: " + helikopter1.getMissiles() + "/16", new Vector2(py+30, px+370), Color.Black);
            }
            game.spriteBatch.End();
        }



        public void draw(GameTime gameTime)
        {
            Game1.konsola.setTraceString("GID", helikopter1.playerId.ToString());
            game.GraphicsDevice.SetRenderTarget(0, renderTarget);

            game.GraphicsDevice.RenderState.AlphaBlendEnable = false;
            game.GraphicsDevice.RenderState.AlphaTestEnable = false;
            game.GraphicsDevice.RenderState.DepthBufferEnable = true;

            game.GraphicsDevice.SamplerStates[0].AddressU = TextureAddressMode.Wrap;
            game.GraphicsDevice.SamplerStates[0].AddressV = TextureAddressMode.Wrap;
            this.gameTime = gameTime;
            foreach (GameObject ob in obiekty)
                ob.draw();

            game.GraphicsDevice.SetRenderTarget(0, null);

            //debugDrawer.Draw(gameTime);
            Texture2D minimapTexture = minimap.draw(game.spriteBatch);

            game.spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            game.GraphicsDevice.Clear(Color.Black);

            Texture2D modelsTexture = renderTarget.GetTexture();
            game.spriteBatch.Draw(modelsTexture, new Rectangle(0, 0, modelsTexture.Width, modelsTexture.Height),
                Color.White);
            //game.spriteBatch.Draw(minimapTexture, new Rectangle(20, 20, minimapTexture.Width, minimapTexture.Height),
            //    Color.White);
            
            game.spriteBatch.Draw(minimapTexture,
                new Vector2(game.GraphicsDevice.PresentationParameters.BackBufferWidth - minimapTexture.Width/2 - 20,
                    minimapTexture.Height / 2 + 20), 
                new Rectangle(0, 0, minimapTexture.Width, minimapTexture.Height),
                new Color(0xff, 0xff, 0xff, 0xaa),
                helikopter1.rotation.Y,
                new Vector2(minimapTexture.Width/2, minimapTexture.Height/2),
                1.0f,
                SpriteEffects.None,
                0.0f);
            game.spriteBatch.End();

            compass.draw(game.spriteBatch, helikopter1.rotation);
            altimeter.draw(game.spriteBatch, helikopter1.position);

            if (drawstats)
            {
                drawStats();
                drawstats = false;
            }
        }

        public void createExplosion(Vector3 pos)
        {
            Explosion exp = new Explosion(game);
            exp.setPos(pos);
            obiekty.Add(exp);
        }
    }
}
